﻿Imports WPFGlue.Framework

Namespace Commanding
    Public MustInherit Class Command
        Inherits CommandBase


        Public Shared ReadOnly CommandProperty As DependencyProperty = DependencyProperty.Register("Command", GetType(RoutedCommand), GetType(Command))
        Public Property Command As RoutedCommand
            Get
                Return GetValue(CommandProperty)
            End Get
            Set(ByVal value As RoutedCommand)
                SetValue(CommandProperty, value)
            End Set
        End Property


        Public Shared ReadOnly PreviewProperty As DependencyProperty = DependencyProperty.Register("Preview", GetType(Boolean), GetType(Command), New PropertyMetadata(False))
        Public Property Preview As Boolean
            Get
                Return GetValue(PreviewProperty)
            End Get
            Set(ByVal value As Boolean)
                SetValue(PreviewProperty, value)
            End Set
        End Property


        Public Shared ReadOnly HandledProperty As DependencyProperty = DependencyProperty.Register("Handled", GetType(Boolean), GetType(Command), New PropertyMetadata(True))
        Public Property Handled As Boolean
            Get
                Return GetValue(HandledProperty)
            End Get
            Set(ByVal value As Boolean)
                SetValue(HandledProperty, value)
            End Set
        End Property

        Private Shared ReadOnly IsRunningPropertyKey As DependencyPropertyKey = DependencyProperty.RegisterReadOnly("IsRunning", GetType(Boolean), GetType(Command), New PropertyMetadata(False))
        Public Shared ReadOnly IsRunningProperty As DependencyProperty = IsRunningPropertyKey.DependencyProperty
        Public Property IsRunning As Boolean
            Get
                Return GetValue(IsRunningProperty)
            End Get
            Protected Set(ByVal value As Boolean)
                SetValue(IsRunningPropertyKey, value)
            End Set
        End Property


        Public Overridable Sub Execute(ByVal sender As Object, ByVal parameter As Object)
            Execute(parameter)
        End Sub

        Public Overridable Sub Execute(ByVal parameter As Object)

        End Sub

        Protected Overridable ReadOnly Property SupportsCanExecute() As Boolean
            Get
                Return UseValidation
            End Get
        End Property

        Public Overridable Function CanExecute(ByVal sender As Object, ByVal parameter As Object) As Boolean
            Return CanExecute(parameter)
        End Function

        Public Overridable Function CanExecute(ByVal parameter) As Boolean
            Return True
        End Function


        Protected Overridable Sub OnExecuted(ByVal sender As Object, ByVal e As ExecutedRoutedEventArgs)
            Exception = Nothing
            IsRunning = True
            Status = WorkingMessage
            CommandManager.InvalidateRequerySuggested()
            Dim a As Func(Of Object, Object, Exception) = AddressOf Me.DoExecute
            Dim op As System.Windows.Threading.DispatcherOperation = Me.Dispatcher.BeginInvoke(a, Windows.Threading.DispatcherPriority.Background, sender, e.Parameter)
            op.Wait()
            Dim success As Boolean = (op.Result Is Nothing)
            If success Then
                Status = ReadyMessage
            Else
                Dim ex As Exception = op.Result
                Status = ex.Message
                Exception = ex
            End If
            IsRunning = False
            CommandManager.InvalidateRequerySuggested()
        End Sub

        Protected Overridable Function DoExecute(ByVal sender As Object, ByVal parameter As Object) As Exception
            Dim result As Exception = Nothing
            Try
                Execute(sender, parameter)
            Catch ex As Exception
                result = ex
            End Try
            Return result
        End Function

        Private Sub OnCanExecute(ByVal sender As Object, ByVal e As CanExecuteRoutedEventArgs)
            Try
                e.CanExecute = Not IsRunning
                If e.CanExecute And UseValidation Then
                    e.CanExecute = Not System.Windows.Controls.Validation.GetHasError(sender)
                End If
                If e.CanExecute And SupportsCanExecute Then
                    e.CanExecute = CanExecute(sender, e.Parameter)
                End If
                e.Handled = Handled
            Catch
                e.Handled = False
            End Try
        End Sub


        Public Shared ReadOnly UseValidationProperty As DependencyProperty = DependencyProperty.Register("UseValidation", GetType(Boolean), GetType(Command))
        Public Property UseValidation As Boolean
            Get
                Return GetValue(UseValidationProperty)
            End Get
            Set(ByVal value As Boolean)
                SetValue(UseValidationProperty, value)
            End Set
        End Property

        Private Shared ReadOnly ExceptionPropertyKey As DependencyPropertyKey = DependencyProperty.RegisterReadOnly("Exception", GetType(Exception), GetType(ActionCommand), New PropertyMetadata())
        Public Shared ReadOnly ExceptionProperty As DependencyProperty = ExceptionPropertyKey.DependencyProperty
        Public Property Exception As Exception
            Get
                Return GetValue(ExceptionProperty)
            End Get
            Protected Set(ByVal value As Exception)
                SetValue(ExceptionPropertyKey, value)
            End Set
        End Property

        Public Shared ReadOnly ReadyMessageProperty As DependencyProperty = DependencyProperty.Register("ReadyMessage", GetType(String), GetType(Command))
        Public Property ReadyMessage As String
            Get
                Return GetValue(ReadyMessageProperty)
            End Get
            Set(ByVal value As String)
                SetValue(ReadyMessageProperty, value)
            End Set
        End Property

        Public Shared ReadOnly WorkingMessageProperty As DependencyProperty = DependencyProperty.Register("WorkingMessage", GetType(String), GetType(Command))
        Public Property WorkingMessage As String
            Get
                Return GetValue(WorkingMessageProperty)
            End Get
            Set(ByVal value As String)
                SetValue(WorkingMessageProperty, value)
            End Set
        End Property


        Private Shared ReadOnly StatusPropertyKey As DependencyPropertyKey = DependencyProperty.RegisterReadOnly("Status", GetType(String), GetType(Command), New PropertyMetadata())
        Public Shared ReadOnly StatusProperty As DependencyProperty = StatusPropertyKey.DependencyProperty
        Public Property Status As String
            Get
                Return GetValue(StatusProperty)
            End Get
            Protected Set(ByVal value As String)
                SetValue(StatusPropertyKey, value)
            End Set
        End Property



        Protected Overrides Sub Attach(ByVal sender As Object)
            If SupportsCanExecute Or UseValidation Then
                StickyComponentManager.Attach(sender, Command, AddressOf OnExecuted, AddressOf OnCanExecute, Preview)
            Else
                StickyComponentManager.Attach(sender, Command, AddressOf OnExecuted, Nothing, Preview)
            End If
        End Sub

        Protected Overrides Sub Detach(ByVal sender As Object)
            StickyComponentManager.Detach(sender, Command)
        End Sub

        Public Overrides Function FindName(name As String) As CommandBase
            Dim result As CommandBase = Nothing
            If Me.Command IsNot Nothing AndAlso Me.Command.Name.Equals(name) Then
                result = Me
            End If
            Return result
        End Function
    End Class

End Namespace
